package com.dylan.channel.v6.future;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class DefaultPromise<V> implements Promise<V>{

    volatile  Object result;

    private static final Object SUCCESS = new Object();


    @Override
    public Promise<V> setSuccess(V result) {
        if (setSuccess0(result)) {
            //唤醒等待线程
            this.notifyAll();
            return this;
        }
        throw new RuntimeException("设置结果失败");
    }

    private boolean setSuccess0(V result) {
        if(!isDone()){
            this.result=result==null?SUCCESS:result;
        }
        return false;
    }

    @Override
    public Promise<V> sync() {
        return null;
    }

    @Override
    public Promise<V> await() {
        return null;
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    @Override
    public boolean isCancelled() {
        return false;
    }

    @Override
    public boolean isDone() {
        return result != null;
    }

    @Override
    public V get() throws InterruptedException, ExecutionException {
        if(isDone()){
            return (V) result;
        }
        await();
        if(!isDone()){
           throw new RuntimeException("虚假唤醒");
        }
        return (V) result;
    }

    @Override
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        if(!isDone()){
            if(!await(timeout,unit)){
                throw new TimeoutException();
            }
        }
        return (V) result;
    }

    @Override
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        return await0(unit.toNanos(timeout));
    }

    private boolean await0(long timeoutNanos) {
        final long startTime = System.nanoTime();
        synchronized (this){
            try {
                long waitTime = timeoutNanos;
                while (!isDone()||waitTime>0){

                    this.wait(timeoutNanos);

                    waitTime = timeoutNanos - (System.nanoTime() - startTime);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        return false;
    }


}
